package dao

import (
	"a-common/constant"
	dom "a-common/domain"
	"a-system/domain/entity"
	"strings"
	"sync"

	"xorm.io/builder"
)

var (
	sysMenuDaoTemp *SysMenuDao
	sysMenuDaoOnce sync.Once
)

type SysMenuDao struct{}

func NewSysMenuDao() *SysMenuDao {
	sysMenuDaoOnce.Do(func() {
		sysMenuDaoTemp = &SysMenuDao{}
	})
	return sysMenuDaoTemp
}

// List 分页
func (m *SysMenuDao) List(args *entity.SysMenuDto, userId int64) (dom.PageVo, error) {
	// 管理员显示所有菜单信息
	if constant.ADMIN_ID == userId {
		return m.ListAll(args)
	} else {
		return m.ListByUserId(args, userId)
	}
}

// ListByUserId 通过用户ID获取菜单列表
func (m *SysMenuDao) ListByUserId(args *entity.SysMenuDto, userId int64) (dom.PageVo, error) {
	// 构建查询条件
	query := pgCli.Table(&entity.SysMenu{}).Join(
		"left",
		"sys_role_menu",
		"sys_role_menu.menu_id = sys_menu.menu_id").Join(
		"left",
		"sys_user_role",
		"sys_user_role.role_id = sys_role_menu.role_id").Join(
		"left",
		"sys_role",
		"sys_role.role_id = sys_user_role.role_id").Where("sys_user_role.user_id = ?", userId)
	if args.MenuName != "" {
		query.And("sys_menu.menu_name Like ?", args.MenuName+"%")
	}
	if args.Visible != "" {
		query.And("sys_menu.visible", args.Visible)
	}
	if args.Status != "" {
		query.And("sys_menu.status", args.Status)
	}
	if args.PageSize != 0 {
		query.Limit(args.PageSize, (args.PageNum-1)*args.PageSize)
	}
	// 查询
	var vPage dom.PageVo
	var rows []entity.SysMenuPageVo
	total, err := query.Asc("sys_menu.parent_id").Asc("sys_menu.order_num").Asc("sys_menu.menu_id").FindAndCount(&rows)
	if err != nil {
		return vPage, err
	}
	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize
	vPage.Rows = rows
	vPage.Total = total
	return vPage, err
}

// ListAll 获取所有
func (m *SysMenuDao) ListAll(args *entity.SysMenuDto) (dom.PageVo, error) {
	var vPage dom.PageVo
	var rows []entity.SysMenuPageVo
	var total int64
	query := pgCli.Table(&entity.SysMenu{}).Where("1 = 1")
	if args.MenuName != "" {
		query.And("menu_name Like ?", args.MenuName+"%")
	}
	if args.Visible != "" {
		query.And("visible = ?", args.Visible)
	}
	if args.Status != "" {
		query.And("status = ?", args.Status)
	}
	if args.IsMenu {
		query.And("menu_type != ?", "F")
	}
	// if args.PageNum != 0 && args.PageSize != 0 {
	// 	query.Limit(args.PageSize, (args.PageNum-1)*args.PageSize)
	// }
	// 查询
	total, err := query.Asc("parent_id").Asc("order_num").Asc("menu_id").FindAndCount(&rows)
	if err != nil {
		return vPage, err
	}

	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize
	vPage.Rows = rows
	vPage.Total = total
	return vPage, err
}

// GetmenuIdsByRoleId 根据角色ID查询菜单树信息
func (m *SysMenuDao) GetmenuIdsByRoleId(roleId int64, menuCheckStrictly bool) ([]int64, error) {
	query := pgCli.Table(&entity.SysMenu{}).Cols("sys_menu.menu_id").Join(
		"left",
		"sys_role_menu",
		"sys_menu.menu_id = sys_role_menu.menu_id").Where("sys_role_menu.role_id = ?", roleId)
	if menuCheckStrictly {
		query.NotIn("sys_menu.menu_id", builder.Select("parent_id").From("sys_menu").Join(
			"inner",
			"sys_role_menu",
			"sys_role_menu.menu_id = sys_menu.menu_id").And(builder.Eq{"sys_role_menu.role_id": roleId}))
	}

	var menuIds []int64
	_, err := query.Asc("parent_id").Asc("order_num").Asc("menu_id").FindAndCount(&menuIds)
	return menuIds, err
}

// Get 查
func (m *SysMenuDao) Get(id string) (entity.SysMenuPageVo, error) {
	var v entity.SysMenuPageVo
	_, err := pgCli.Table(&entity.SysMenu{}).ID(id).Get(&v)
	return v, err
}

// Add 增
func (m *SysMenuDao) Add(args *entity.SysMenuDto) (int64, error) {
	return pgCli.InsertOne(&entity.SysMenu{
		MenuName:  args.MenuName,
		ParentId:  args.ParentId,
		OrderNum:  args.OrderNum,
		Path:      args.Path,
		Component: args.Component,
		Query:     args.Query,
		IsFrame:   args.IsFrame,
		IsCache:   args.IsCache,
		MenuType:  args.MenuType,
		Visible:   args.Visible,
		Status:    args.Status,
		Perms:     args.Perms,
		Icon:      args.Icon,
		BaseStruct: dom.BaseStruct{
			CreatedBy: args.CreatedBy,
			UpdatedBy: args.CreatedBy,
			Remark:    args.Remark,
		},
	})
}

// Edit 改
func (m *SysMenuDao) Edit(args *entity.SysMenuDto) (int64, error) {
	return pgCli.ID(args.MenuId).Update(
		&entity.SysMenu{
			MenuName:  args.MenuName,
			ParentId:  args.ParentId,
			OrderNum:  args.OrderNum,
			Path:      args.Path,
			Component: args.Component,
			Query:     args.Query,
			IsFrame:   args.IsFrame,
			IsCache:   args.IsCache,
			MenuType:  args.MenuType,
			Visible:   args.Visible,
			Status:    args.Status,
			Perms:     args.Perms,
			Icon:      args.Icon,
			BaseStruct: dom.BaseStruct{
				UpdatedBy: args.UpdatedBy,
				Remark:    args.Remark,
			},
		})
}

// Del 删
func (m *SysMenuDao) Del(ids string) (int64, error) {
	return pgCli.In("menu_id", strings.Split(ids, `,`)).Unscoped().Delete(&entity.SysMenu{})
}

// FileMenuByRoleIds 通过RoleId获取权限信息
func (m *SysMenuDao) FileMenuByRoleIds(roleIds []int64) ([]*entity.SysMenuPageVo, error) {
	var v []*entity.SysMenuPageVo

	isAdmin := false
	for _, it := range roleIds {
		if it == 1 {
			isAdmin = true
			break
		}
	}
	if isAdmin {
		// 嵌套查询
		err := pgCli.Table(&entity.SysMenu{}).Find(&v)
		return v, err
	}
	// 嵌套查询
	err := pgCli.Table(&entity.SysMenu{}).In("menu_id", builder.Select("menu_id").From("sys_role_menu").Where(builder.In("role_id", roleIds))).Find(&v)
	return v, err
}
